package com.gitee.chili.leisure.filter;


import cn.hutool.json.JSONUtil;
import com.gitee.chili.leisure.ResponseCode;
import com.gitee.chili.leisure.ResponseResult;
import com.gitee.chili.leisure.properties.FilterProperties;
import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@SuppressWarnings("all")
@Slf4j
@Component
public class RateLimitFilter extends ZuulFilter {

    @Autowired
    private FilterProperties properties;

    /**
     * Guava 限流控制器
     * 每秒1个令牌，实际通过压测获得
     */
    private static final RateLimiter RATE_LIMITER = RateLimiter.create(1);

    /**
     * 是否执行该过滤器
     *
     * @return true 代表需要过滤
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 核心处理方法
     */
    @Override
    public Object run() throws ZuulException {

        // 获取上下文
        RequestContext ctx = RequestContext.getCurrentContext();
        ctx.getResponse().setContentType("text/html;charset=UTF-8");
        HttpServletRequest request = ctx.getRequest();
        log.info("{} current limiting filter request to {}", request.getMethod(), request.getRequestURL());
        // 拿不到令牌马上返回。
        if (!RATE_LIMITER.tryAcquire()) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
            ctx.setResponseBody(JSONUtil.toJsonStr(ResponseResult.failure(ResponseCode.SERVER_BUSY)));
        }
        return null;
    }

    /**
     * 表示一个过滤器的类型，这里是一个前置过滤器
     *
     * @return "PRE"
     */
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    /**
     * 优先级设置，数值越小越优先
     * 限流要最早
     *
     * @return -10
     */
    @Override
    public int filterOrder() {
        return -10;
    }

}
